package qc.module.cms.service;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONException;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cloud.client.ServiceInstance;
import org.springframework.cloud.client.discovery.DiscoveryClient;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Service;
import org.springframework.web.client.RestTemplate;
import qc.common.core.enums.ResourceStatusFlagEnum;
import qc.common.core.exception.QCPromptException;
import qc.common.core.unify.QCUnifyReturnValue;
import qc.module.cms.dto.category.*;
import qc.module.cms.entity.Article;
import qc.module.cms.entity.Category;
import qc.module.cms.entity.CategoryDept;
import qc.module.cms.mapper.CategoryMapper;
import qc.module.cms.repository.ArticleRepository;
import qc.module.cms.repository.CategoryRepository;
import qc.module.platform.dto.dept.DeptDto;
import qc.module.platform.dto.file.FileInfoDto;

import java.util.*;
import java.util.stream.Collectors;

/**
 * CategoryService
 *
 * @author QuCheng Tech
 * @since 2023/5/26
 */
@Service
public class CategoryService {
    private CategoryRepository repository;

    @Autowired
    public void setCategoryRepository(CategoryRepository repository) {
        this.repository = repository;
    }

    private ArticleRepository articleRepository;

    @Autowired
    public void setArticleRepository(ArticleRepository articleRepository) {
        this.articleRepository = articleRepository;
    }

    private CategoryDeptService categoryDeptService;

    @Autowired
    public void setCategoryDeptService(CategoryDeptService categoryDeptService) {
        this.categoryDeptService = categoryDeptService;
    }

    @Autowired
    private RestTemplate restTemplate;

    @Autowired
    private DiscoveryClient discoveryClient;

    /**
     * 查询栏目，返回详细信息；查询条件可以为空，条件中可指定是否包含所有状态的栏目、根据部门进行过滤条件；
     *
     * @param condition   查询条件
     * @param userDeptIds 访问用户有权限的部门ID集合，可以为null
     * @return 栏目详细信息列表
     * @author QuCheng Tech
     * @since 2023/5/26
     */
    public List<CategoryDto> queryListDetail(CategoryQueryConditionDto condition, List<Integer> userDeptIds) throws QCPromptException {
        List<Category> ens = query(condition, userDeptIds);
        if (ens != null && ens.size() > 0x0) {
            //先将Entity集合转换为DTO集合，将对DTO集合按层级关系进行排序
            List<CategoryDto> dtos = CategoryMapper.MAPPER.toDtoList(ens);
            //按层级和排序后的DTO集合
            List<CategoryDto> orderByLevelDtos = new ArrayList<>();
            List<CategoryDto> rootCategories = dtos.stream().filter(p -> p.getPid() == 0x0).collect(Collectors.toList());
            if (rootCategories != null && rootCategories.size() > 0x0) {
                //遍历一级栏目，添加到返回集合中，获取二级栏目
                for (CategoryDto level1CategoryDto : rootCategories) {
                    //设置栏目level为1
                    level1CategoryDto.setLevel(0x1);
                    orderByLevelDtos.add(level1CategoryDto);
                    List<CategoryDto> level2Categories = dtos.stream().filter(p -> level1CategoryDto.getId() == (p.getPid())).collect(Collectors.toList());
                    if (level2Categories != null && level2Categories.size() > 0x0) {
                        //遍历二级栏目，添加到返回集合中，获取三级栏目
                        for (CategoryDto level2CategoryDto : level2Categories) {
                            //设置栏目level为2
                            level2CategoryDto.setLevel(0x2);
                            orderByLevelDtos.add(level2CategoryDto);
                            //如果需要获取三级栏目，在此添加
                        }
                    }
                }

                //返回按层级排序后的DTO集合
                return orderByLevelDtos;
            }
        }

        return null;
    }

    /**
     * 查询栏目，返回详细信息；查询条件可以为空，条件中可指定是否包含所有状态的栏目、根据部门进行过滤条件；
     *
     * @param condition       查询条件
     * @param userDeptIds     访问用户有权限的部门ID集合，可以为null
     * @param returnTreeLevel 返回的树层级
     * @return 栏目详细信息树
     * @author QuCheng Tech
     * @since 2023/6/3
     */
    public List<CategoryTreeDto> queryTreeDetail(CategoryQueryConditionDto condition, List<Integer> userDeptIds, int returnTreeLevel) throws QCPromptException {
        List<Category> ens = query(condition, userDeptIds);
        if (ens != null && ens.size() > 0x0) {
            //先将Entity集合转换为DTO集合，将对DTO集合按层级关系进行排序
            List<CategoryDto> dtos = CategoryMapper.MAPPER.toDtoList(ens);
            //按层级和排序后的DTO集合
            List<CategoryTreeDto> result = new ArrayList<>();
            List<CategoryDto> rootCategories = dtos.stream().filter(p -> p.getPid() == 0x0).collect(Collectors.toList());
            if (rootCategories != null && rootCategories.size() > 0x0) {
                //遍历一级栏目，添加到返回集合中，获取二级栏目
                for (CategoryDto level1CategoryDto : rootCategories) {
                    //设置栏目level为1
                    level1CategoryDto.setLevel(0x1);

                    //树形结构1级节点
                    CategoryTreeDto level1TreeNode = new CategoryTreeDto();
                    level1TreeNode.setInfo(level1CategoryDto);

                    //判断返回树形结构需要需要获取第2级
                    if (returnTreeLevel >= 0x2) {
                        List<CategoryDto> level2Categories = dtos.stream().filter(p -> level1CategoryDto.getId() == (p.getPid())).collect(Collectors.toList());
                        if (level2Categories != null && level2Categories.size() > 0x0) {
                            List<CategoryTreeDto> level1TreeNodeChilds = new ArrayList<>();

                            //遍历二级栏目，添加到返回集合中，获取三级栏目
                            for (CategoryDto level2CategoryDto : level2Categories) {
                                //设置栏目level为2
                                level2CategoryDto.setLevel(0x2);

                                //树形结构2级节点
                                CategoryTreeDto level2TreeNode = new CategoryTreeDto();
                                level2TreeNode.setInfo(level2CategoryDto);

                                //判断返回树形结构需要需要获取第3级
                                if (returnTreeLevel >= 0x3) {
                                    List<CategoryDto> level3Categories = dtos.stream().filter(p -> level2CategoryDto.getId() == (p.getPid())).collect(Collectors.toList());
                                    if (level3Categories != null && level3Categories.size() > 0x0) {
                                        List<CategoryTreeDto> level2TreeNodeChilds = new ArrayList<>();

                                        //遍历三级栏目，添加到返回集合中，获取四级栏目
                                        for (CategoryDto level3CategoryDto : level3Categories) {
                                            //设置栏目level为3
                                            level3CategoryDto.setLevel(0x3);

                                            //树形结构3级节点
                                            CategoryTreeDto level3TreeNode = new CategoryTreeDto();
                                            level3TreeNode.setInfo(level3CategoryDto);

                                            //大于4级的暂时不进行获取，后继可进行添加

                                            //添加2级节点的知子节点
                                            level2TreeNodeChilds.add(level3TreeNode);
                                        }

                                        level2TreeNode.setChilds(level2TreeNodeChilds);
                                    }
                                }

                                //添加1级节点的知子节点
                                level1TreeNodeChilds.add(level2TreeNode);
                            }

                            level1TreeNode.setChilds(level1TreeNodeChilds);
                        }
                    }

                    result.add(level1TreeNode);
                }

                return result;
            }
        }

        return null;
    }

    /**
     * 查询栏目，返回简要信息（仅包含ID、名称和层级）；查询条件可以为空，条件中可指定是否包含所有状态的栏目、根据部门进行过滤条件；
     * 返回结果包括用户所在部门有权限的栏目、不按部门控制权限的栏目、有子栏目权限但父栏目不在返回结果中的栏目
     *
     * @param condition   查询条件
     * @param userDeptIds 访问用户有权限的部门ID集合，可以为null
     * @param maxCategoryLevel 需要返回的最大显示层级数
     * @return 栏目简要信息列表
     * @author QuCheng Tech
     * @since 2024/1/11
     */
    public List<CategorySimpleDto> queryDtoListSimple(CategoryQueryConditionDto condition, List<Integer> userDeptIds,Integer maxCategoryLevel) throws QCPromptException {
        //1.获取用户有权限的所有栏目集合（有部门权限、栏目不按部门控制权限、有子栏目权限但没有父栏目没有的栏目）
        List<CategorySimpleDto> result = getValidCategories(condition,userDeptIds);
        
        //2.定义最后返回的结果集
        List<CategorySimpleDto> returnResult = new ArrayList<>();
        
        //3.处理结果集result，按层级和排序后的DTO集合，层级从0层开始
        if (CollectionUtils.isNotEmpty(result)){
            //3.1 获取一级栏目集合，循环遍历
            List<CategorySimpleDto> rootCategories = result.stream().filter(dto -> dto.getPid() == 0x0).collect(Collectors.toList());
            if (CollectionUtils.isNotEmpty(rootCategories)){
                rootCategories.stream().forEach(rootCategory -> {
                    //3.1.1 一级栏目添加到返回集合中
                    returnResult.add(rootCategory);
                    //3.1.2 添加一级栏目的子栏目
                    addSubListCategories(returnResult,result,rootCategory,rootCategory.getLevel(),maxCategoryLevel);
                });
            }
        }
        
        //4.返回最后结果集
        return returnResult;
    }

    /**
     * 为当前层级的栏目添加子栏目
     * 栏目层级从0开始
     * @param result 最终返回的结果集
     * @param dtoList 处理的栏目集合
     * @param currentCategory 上级栏目
     * @param level 上级栏目层级
     * @param maxCategoryLevel 最大显示层级数
     */
    private void addSubListCategories(List<CategorySimpleDto> result, List<CategorySimpleDto> dtoList,
                                      CategorySimpleDto currentCategory, Integer level,Integer maxCategoryLevel) {

        //1.判断子栏目层级不超过返回树形结构最大显示层级则添加到子节点（根节点层级从0开始，最大层级减一计算）
        if (level + 0x1 <= maxCategoryLevel - 0x1){
            //2.获取当前栏目的子栏目集合
            List<CategorySimpleDto> subCategories = dtoList.stream()
                    .filter(category -> category.getPid() == currentCategory.getId()).collect(Collectors.toList());

            //3.循环遍历子栏目集合
            subCategories.stream().forEach(subCategory -> {
                //3.1 设置子栏目层级
                subCategory.setLevel(level + 0x1);

                //3.2 子栏目添加都结果集
                result.add(subCategory);

                //3.3 添加当前子栏目的下级栏目
                addSubListCategories(result, dtoList, subCategory, subCategory.getLevel(),maxCategoryLevel);
            });
        }
    }

    /**
     * 查询所有正常状态的栏目
     * layout等不需要的属性内容不查，状态正常的
     * @return 栏目集合
     * @author QuCheng Tech
     * @since 2024/1/12
     */
    private  List<Category> queryAllValid(){
        LambdaQueryWrapper<Category> wrapper = new LambdaQueryWrapper<>();
        wrapper.select(Category::getId,Category::getPid,Category::getVisible,Category::getName,
                Category::isCandraft,Category::isDeptauth);
        wrapper.eq(Category::getFlag, ResourceStatusFlagEnum.NORMAL);
        return repository.selectList(wrapper);
    }

    /**
     * 获取用户有权限的所有栏目集合（有部门权限、栏目不按部门控制权限、有子栏目权限但没有父栏目没有的栏目）
     * 
     * @param condition
     * @param userDeptIds 用户部门id集合
     * @return 用户有权限的所有部门
     * @author QuCheng Tech
     * @since 2024/1/12
     * @throws QCPromptException
     */
    private List<CategorySimpleDto> getValidCategories(CategoryQueryConditionDto condition, List<Integer> userDeptIds) throws QCPromptException {
        //1.查询所有栏目集合（layout等不需要的属性内容不查，状态正常的）
        List<Category> allCategories = queryAllValid();

        //2.定义结果集
        List<CategorySimpleDto> result = new ArrayList<>();

        if (CollectionUtils.isNotEmpty(allCategories)) {
            //3.enList转换为dtoList
            List<CategorySimpleDto> dtoList = CategoryMapper.MAPPER.toSimpleDtoList(allCategories);

            //4.查询用户部门有权限的栏目id集合
            List<Integer> filterCategoryIds;
            if (Objects.nonNull(condition) && condition.isIsdept()) {
                if (CollectionUtils.isEmpty(userDeptIds) || userDeptIds.size() < 0x1)
                    return null;
                //查询所有栏目与部门关联关系，与传入的用户部门集合取交集作为查询条件传入
                filterCategoryIds = categoryDeptService.getValidCategoryIds(userDeptIds);
            } else {
                filterCategoryIds = new ArrayList<>();
            }

            //5.定义有栏目权限的结果id集合idsMap<cid,candraft>
            Map<Integer,Boolean> idsMap = new HashMap<>();

            //6.循环遍历所有栏目集合
            if (CollectionUtils.isNotEmpty(dtoList)){
                dtoList.stream().forEach(category -> {
                    //6.1 如果不按部门控制权限，直接添加到idsMap
                    if (!category.isDeptauth()) idsMap.put(category.getId(),category.isCandraft());

                    //6.2 如果按部门控制权限：
                    if (category.isDeptauth()){
                        //6.2.1 判断栏目id在用户部门有权限的栏目id集合中是否存在，存在则添加到idsMap；不存在则不添加。
                        boolean isExist = filterCategoryIds.stream().filter(cid -> cid.equals(category.getId())).findAny().isPresent();
                        if (isExist) idsMap.put(category.getId(),category.isCandraft());
                    }

                });
            }

            //7.定义最终需要的所有栏目id集合map
            Map<Integer,Boolean> resultIdsMap = new HashMap<>();

            //8.循环遍历栏目结果id集合idsMap，添加到最终的id集合resultIdsMap中，如果父栏目不存在idsMap中，将父栏目也添加进去
            for (Integer key:idsMap.keySet()){
                resultIdsMap.put(key,idsMap.get(key));
                //8.1 从所有栏目集合中找出当前栏目
                CategorySimpleDto currentCategory = dtoList.stream().filter(category -> category.getId() == key).findAny().orElse(null);
                //8.2 判断当前栏目的父栏目id在idsMap是否存在，如果不存在，父id添加到idsMap，不允许发文
                if (currentCategory.getPid() != 0x0){
                    if (!idsMap.containsKey(currentCategory.getPid())) resultIdsMap.put(currentCategory.getPid(),false);
                }
            }

            //9.循环遍历最终的栏目结果id集合resultIdsMap，将resultIdsMap中所有栏目找出来存放到结果集中
            for (Integer key:resultIdsMap.keySet()){
                //从所有栏目集合中找出当前栏目，设置candraft的值，然后添加到结果集中
                CategorySimpleDto dto = dtoList.stream().filter(category -> category.getId() == key).findAny().orElse(null);
                dto.setCandraft(resultIdsMap.get(key));
                result.add(dto);
            }
        }
        
        //10.返回结果集
        return result;
    }


    /**
     * 查询栏目，返回简要信息（仅包含ID、名称和层级）；查询条件可以为空，条件中可指定是否包含所有状态的栏目、根据部门进行过滤条件；
     *
     * @param condition   查询条件
     * @param userDeptIds 访问用户有权限的部门ID集合，可以为null
     * @return 栏目简要信息列表
     * @author QuCheng Tech
     * @since 2023/5/27
     */
    public List<CategorySimpleDto> queryListSimple(CategoryQueryConditionDto condition, List<Integer> userDeptIds) throws QCPromptException {
        List<Category> ens = query(condition, userDeptIds);
        if (ens != null && ens.size() > 0x0) {
            //先将Entity集合转换为DTO集合，将对DTO集合按层级关系进行排序
            List<CategorySimpleDto> dtos = CategoryMapper.MAPPER.toSimpleDtoList(ens);
            //按层级和排序后的DTO集合
            List<CategorySimpleDto> orderByLevelDtos = new ArrayList<>();
            List<CategorySimpleDto> rootCategories = dtos.stream().filter(p -> p.getPid() == 0x0).collect(Collectors.toList());
            if (rootCategories != null && rootCategories.size() > 0x0) {
                //遍历一级栏目，添加到返回集合中，获取二级栏目
                for (CategorySimpleDto level1CategoryDto : rootCategories) {
                    //设置栏目level为1
                    level1CategoryDto.setLevel(0x1);
                    orderByLevelDtos.add(level1CategoryDto);
                    List<CategorySimpleDto> level2Categories = dtos.stream().filter(p -> level1CategoryDto.getId() == (p.getPid())).collect(Collectors.toList());
                    if (level2Categories != null && level2Categories.size() > 0x0) {
                        //遍历二级栏目，添加到返回集合中，获取三级栏目
                        for (CategorySimpleDto level2CategoryDto : level2Categories) {
                            //设置栏目level为2
                            level2CategoryDto.setLevel(0x2);
                            orderByLevelDtos.add(level2CategoryDto);
                            //如果需要获取三级栏目，在此添加
                        }
                    }
                }

                //返回按层级排序后的DTO集合
                return orderByLevelDtos;
            }
        }

        return null;
    }
   
    /**
     * 查询栏目树结构简要信息，返回简要信息（仅包含ID、名称和层级）；查询条件可以为空，条件中可指定是否包含所有状态的栏目、根据部门进行过滤条件；
     *
     * @param condition       查询条件
     * @param userDeptIds     访问用户有权限的部门ID集合，可以为null
     * @param maxCategoryLevel 返回最大显示的树层级
     * @return 栏目简要信息树
     * @author QuCheng Tech
     * @since 2023/6/3
     * @update 2024/1/12
     */
    public List<CategoryTreeSimpleDto> queryTreeSimple(CategoryQueryConditionDto condition, List<Integer> userDeptIds, Integer maxCategoryLevel) throws QCPromptException {
        //1.获取用户有权限的所有栏目集合（有部门权限、栏目不按部门控制权限、有子栏目权限但没有父栏目没有的栏目）
        List<CategorySimpleDto> result = getValidCategories(condition,userDeptIds);

        //2.定义最后返回的结果集
        List<CategoryTreeSimpleDto> returnResult = new ArrayList<>();

        //3.处理结果集result，按层级和排序后的DTO集合，层级从1层开始
        if (CollectionUtils.isNotEmpty(result)){
            //3.1 获取一级栏目集合，循环遍历
            List<CategorySimpleDto> rootCategories = result.stream().filter(dto -> dto.getPid() == 0x0).collect(Collectors.toList());
            if (CollectionUtils.isNotEmpty(rootCategories)){
                rootCategories.stream().forEach(rootCategory -> {
                    //3.1.1 设置栏目层级为1
                    rootCategory.setLevel(0x1);
                    //3.1.2 定义树形结构1级节点，当前栏目设置给1级节点
                    CategoryTreeSimpleDto rootTreeNode = new CategoryTreeSimpleDto();
                    rootTreeNode.setInfo(rootCategory);
                    //3.1.3 继续添加当前栏目的下级栏目节点
                    //3.1.3.1 定义下级子节点集合，递归添加栏目的下级栏目节点
                    List<CategoryTreeSimpleDto> subTreeNodeChilds = new ArrayList<>();
                    addSubTreeCategories(subTreeNodeChilds,result,rootCategory,rootCategory.getLevel(),maxCategoryLevel);
                    rootTreeNode.setChilds(subTreeNodeChilds);
                    //3.1.4 将1级节点添加到结果集returnResult中
                    returnResult.add(rootTreeNode);
                });
            }
        }
        
        //4.返回最终结果集
        return returnResult;
    }
    //public List<CategoryTreeSimpleDto> queryTreeSimple(CategoryQueryConditionDto condition, List<Integer> userDeptIds, int returnTreeLevel) throws QCPromptException {
    //    List<Category> ens = query(condition, userDeptIds);
    //    if (ens != null && ens.size() > 0x0) {
    //        //先将Entity集合转换为DTO集合，将对DTO集合按层级关系进行排序
    //        List<CategorySimpleDto> dtos = CategoryMapper.MAPPER.toSimpleDtoList(ens);
    //        //按层级和排序后的DTO集合
    //        List<CategoryTreeSimpleDto> result = new ArrayList<>();
    //        List<CategorySimpleDto> rootCategories = dtos.stream().filter(p -> p.getPid() == 0x0).collect(Collectors.toList());
    //        if (rootCategories != null && rootCategories.size() > 0x0) {
    //            //遍历一级栏目，添加到返回集合中，获取二级栏目
    //            for (CategorySimpleDto level1CategoryDto : rootCategories) {
    //                //设置栏目level为1
    //                level1CategoryDto.setLevel(0x1);
    //
    //                //树形结构1级节点
    //                CategoryTreeSimpleDto level1TreeNode = new CategoryTreeSimpleDto();
    //                level1TreeNode.setInfo(level1CategoryDto);
    //
    //                //判断返回树形结构需要需要获取第2级
    //                if (returnTreeLevel >= 0x2) {
    //                    List<CategorySimpleDto> level2Categories = dtos.stream().filter(p -> level1CategoryDto.getId() == (p.getPid())).collect(Collectors.toList());
    //                    if (level2Categories != null && level2Categories.size() > 0x0) {
    //                        List<CategoryTreeSimpleDto> level1TreeNodeChilds = new ArrayList<>();
    //
    //                        //遍历二级栏目，添加到返回集合中，获取三级栏目
    //                        for (CategorySimpleDto level2CategoryDto : level2Categories) {
    //                            //设置栏目level为2
    //                            level2CategoryDto.setLevel(0x2);
    //
    //                            //树形结构2级节点
    //                            CategoryTreeSimpleDto level2TreeNode = new CategoryTreeSimpleDto();
    //                            level2TreeNode.setInfo(level2CategoryDto);
    //
    //                            //判断返回树形结构需要需要获取第3级
    //                            if (returnTreeLevel >= 0x3) {
    //                                List<CategorySimpleDto> level3Categories = dtos.stream().filter(p -> level2CategoryDto.getId() == (p.getPid())).collect(Collectors.toList());
    //                                if (level3Categories != null && level3Categories.size() > 0x0) {
    //                                    List<CategoryTreeSimpleDto> level2TreeNodeChilds = new ArrayList<>();
    //
    //                                    //遍历三级栏目，添加到返回集合中，获取四级栏目
    //                                    for (CategorySimpleDto level3CategoryDto : level3Categories) {
    //                                        //设置栏目level为3
    //                                        level3CategoryDto.setLevel(0x3);
    //
    //                                        //树形结构3级节点
    //                                        CategoryTreeSimpleDto level3TreeNode = new CategoryTreeSimpleDto();
    //                                        level3TreeNode.setInfo(level3CategoryDto);
    //
    //                                        //大于4级的暂时不进行获取，后继可进行添加
    //
    //                                        //添加2级节点的知子节点
    //                                        level2TreeNodeChilds.add(level3TreeNode);
    //                                    }
    //
    //                                    level2TreeNode.setChilds(level2TreeNodeChilds);
    //                                }
    //                            }
    //
    //                            //添加1级节点的知子节点
    //                            level1TreeNodeChilds.add(level2TreeNode);
    //                        }
    //
    //                        level1TreeNode.setChilds(level1TreeNodeChilds);
    //                    }
    //                }
    //
    //                result.add(level1TreeNode);
    //            }
    //
    //            return result;
    //        }
    //    }
    //
    //    return null;
    //}

    /**
     * 为上级栏目添加子栏目
     * 
     * @param superTreeNodeChilds 上级节点的子节点
     * @param result 需要处理的结果集
     * @param rootCategory 上级栏目
     * @param level 上级栏目层级
     * @param maxCategoryLevel 栏目最大显示层级
     */
    private void addSubTreeCategories(List<CategoryTreeSimpleDto> superTreeNodeChilds, List<CategorySimpleDto> result,
                                  CategorySimpleDto rootCategory, Integer level,Integer maxCategoryLevel) {
        //1.判断子栏目层级不超过返回树形结构最大显示层级则添加到子节点（根节点层级从1开始）
        if (level + 0x1 <= maxCategoryLevel){
            //2.获取子栏目集合
            List<CategorySimpleDto> subCategories = result.stream().filter(dto -> dto.getPid() == rootCategory.getId()).collect(Collectors.toList());
            if (CollectionUtils.isNotEmpty(subCategories)){
                //3.循环遍历子节点
                subCategories.stream().forEach(subCategory -> {
                    //3.1 设置子栏目层级为父栏目层级+1
                    subCategory.setLevel(level + 0x1);
                    //3.2 定义树形结构子节点，当前子栏目添加到子节点
                    CategoryTreeSimpleDto subTreeNode = new CategoryTreeSimpleDto();
                    subTreeNode.setInfo(subCategory);
                    //3.3 继续添加当前子栏目的下级栏目节点
                    //3.3.1 定义下级子节点集合，递归添加子栏目的下级栏目节点
                    List<CategoryTreeSimpleDto> subTreeNodeChilds = new ArrayList<>();
                    addSubTreeCategories(subTreeNodeChilds,result,subCategory,subCategory.getLevel(),maxCategoryLevel);
                    subTreeNode.setChilds(subTreeNodeChilds);

                    //3.4 添加子栏目节点到上级节点的子节点集合中
                    superTreeNodeChilds.add(subTreeNode);
                });
            }
        }
    }
    
    /**
     * 查询条件中指定是否包含所有状态的栏目、根据部门进行过滤条件；结果以TreeTable组件要求的数据格式返回各栏目的详细信息；
     *
     * @param condition:       查询条件
     * @param userDeptIds:     拥有权限的部门id集合
     * @param returnTreeLevel: 需要查询的层级
     * @return List<CategoryTreeTableDetailDto> 返回各栏目的详细信息
     * @author QcCheng Tech
     * @date 2023/8/2
     */
    public List<CategoryTreeTableDetailDto> queryTreeTableDetail(CategoryQueryConditionDto condition, List<Integer> userDeptIds, int returnTreeLevel) throws QCPromptException {
        List<Category> ens = query(condition, userDeptIds);
        if (ens != null && ens.size() > 0x0) {
            //先将Entity集合转换为DTO集合，将对DTO集合按层级关系进行排序
            List<CategoryTreeTableDetailDto> dtos = CategoryMapper.MAPPER.toTreeTableDetailDtoList(ens);
            //按层级和排序后的DTO集合
            List<CategoryTreeTableDetailDto> rootCategories = dtos.stream().filter(p -> p.getPid() == 0x0).collect(Collectors.toList());
            if (rootCategories != null && rootCategories.size() > 0x0) {
                //遍历一级栏目，添加到返回集合中，获取二级栏目
                for (CategoryTreeTableDetailDto level1CategoryDto : rootCategories) {
                    //设置栏目level为1
                    level1CategoryDto.setLevel(0x1);
                    level1CategoryDto.setLabel(level1CategoryDto.getName());
                    level1CategoryDto.setValue(level1CategoryDto.getId());
                    //判断返回树形结构需要需要获取第2级
                    if (returnTreeLevel >= 0x2) {
                        List<CategoryTreeTableDetailDto> level2Categories = dtos.stream().filter(p -> level1CategoryDto.getId() == (p.getPid())).collect(Collectors.toList());
                        if (level2Categories != null && level2Categories.size() > 0x0) {
                            //遍历二级栏目，添加到返回集合中，获取三级栏目
                            for (CategoryTreeTableDetailDto level2CategoryDto : level2Categories) {
                                //设置栏目level为2
                                level2CategoryDto.setLevel(0x2);
                                level2CategoryDto.setLabel(level2CategoryDto.getName());
                                level2CategoryDto.setValue(level2CategoryDto.getId());

                                //判断返回树形结构需要需要获取第3级
                                if (returnTreeLevel >= 0x3) {
                                    List<CategoryTreeTableDetailDto> level3Categories = dtos.stream().filter(p -> level2CategoryDto.getId() == (p.getPid())).collect(Collectors.toList());
                                    if (level3Categories != null && level3Categories.size() > 0x0) {
                                        //遍历三级栏目，添加到返回集合中，获取四级栏目
                                        for (CategoryTreeTableDetailDto level3CategoryDto : level3Categories) {
                                            //设置栏目level为3
                                            level3CategoryDto.setLevel(0x3);
                                            level3CategoryDto.setLabel(level3CategoryDto.getName());
                                            level3CategoryDto.setValue(level3CategoryDto.getId());
                                            //大于4级的暂时不进行获取，后继可进行添加
                                        }
                                        level2CategoryDto.setChildren(level3Categories);
                                    }
                                }

                            }
                            level1CategoryDto.setChildren(level2Categories);
                        }
                    }
                }

                return rootCategories;
            }
        }
        return null;
    }


    /**
     * 查询栏目，返回Entity对象；供返回DTO对象方法调用，根据需要进行不同的映射转换
     *
     * @param condition   查询条件
     * @param userDeptIds 访问用户有权限的部门ID集合，可以为null
     * @return 栏目Entity集合
     * @author QuCheng Tech
     * @since 2023/5/26
     */
    List<Category> query(CategoryQueryConditionDto condition, List<Integer> userDeptIds) throws QCPromptException {
        //如果查询条件中指定需要根据部门过滤，用户对应的部门ID集合为空，不需要查询，返回null
        //得到最后查询过滤使用的部门ID集合
        List<Integer> filterCategoryIds = null;
        if (condition != null && condition.isIsdept()) {
            if (userDeptIds == null || userDeptIds.size() < 0x1)
                return null;
            //查询所有栏目与部门关联关系，与传入的用户部门集合取交集作为查询条件传入
            filterCategoryIds = categoryDeptService.getValidCategoryIds(userDeptIds);
        }

        LambdaQueryWrapper<Category> wrapper = new LambdaQueryWrapper<>();
        if (condition != null) {
            if (!condition.isIsall()) {
                //查询条件，如果状态不是所有的，仅查询正常状态的
                wrapper.eq(Category::getFlag, ResourceStatusFlagEnum.NORMAL);
            }
            if (condition.isIsdept()) {
                wrapper.in(Category::getId, filterCategoryIds);
            }
            //判断是否包含在菜单上不显示的栏目，为true表示不管栏目是否在菜单上显示与否，为false表示只包含在菜单上显示的栏目
            if (!condition.isIsvisible()) {
                wrapper.eq(Category::getVisible, true);
            }
        }
        //排序
        wrapper.orderByAsc(Category::getOdr);
        wrapper.orderByAsc(Category::getId);

        //查询数据
        return repository.selectList(wrapper);
    }

    /**
     * 获取指定ID的栏目信息
     *
     * @param id    栏目ID
     * @param valid 有效标识，为true表示需判断状态为有效，为false表示不进行状态判断
     * @return 栏目信息
     * @author QuCheng Tech
     * @since 2023/5/27
     */
    public CategoryDto get(Integer id, boolean valid) throws QCPromptException {
        if (id == null)
            throw new QCPromptException("栏目ID不能为空");

        LambdaQueryWrapper<Category> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(Category::getId, id);
        if (valid)
            wrapper.eq(Category::getFlag, ResourceStatusFlagEnum.NORMAL);

        Category category = repository.selectOne(wrapper);

        if (category != null)
            return CategoryMapper.MAPPER.CategoryEntityToDto(category);

        return null;
    }

    /**
     * 获取指定ID集合的栏目信息
     *
     * @param ids    栏目ID集合
     * @param valid 有效标识，为true表示需判断状态为有效，为false表示不进行状态判断
     * @return 栏目信息
     * @author QuCheng Tech
     * @since 2024/9/2
     */
    public List<CategoryDto> getByIdsBatch(List<Integer> ids,boolean valid) throws QCPromptException {
        if (ids == null)
            throw new QCPromptException("栏目ID不能为空");

        LambdaQueryWrapper<Category> wrapper = new LambdaQueryWrapper<>();
        wrapper.in(Category::getId, ids);
        if (valid)
            wrapper.eq(Category::getFlag, ResourceStatusFlagEnum.NORMAL);

        List<Category> categorys = repository.selectList(wrapper);

        if (categorys != null)
            return CategoryMapper.MAPPER.toDtoList(categorys);

        return null;
    }

    /**
     * 获取指定ID的下一级栏目信息
     *
     * @param id    栏目ID
     * @param valid 有效标识，为true表示需判断状态为有效，为false表示不进行状态判断
     * @return 栏目信息
     * @author QuCheng Tech
     * @since 2023/5/29
     */
    public List<CategoryDto> getChilds(Integer id, boolean valid) throws QCPromptException {
        if (id == null)
            throw new QCPromptException("栏目ID不能为空");
        LambdaQueryWrapper<Category> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(Category::getPid, id);
        if (valid)
            wrapper.eq(Category::getFlag, ResourceStatusFlagEnum.NORMAL);

        wrapper.orderByAsc(Category::getOdr);
        wrapper.orderByAsc(Category::getId);
        List<Category> ens = repository.selectList(wrapper);
        if (ens != null && ens.size() > 0x0)
            return CategoryMapper.MAPPER.toDtoList(ens);

        return null;
    }

    /**
     * 新增栏目
     *
     * @param dto 栏目信息
     * @return 成功返回null
     * @author QuCheng Tech
     * @since 2023/5/27
     */
    public String add(CategoryAddDto dto,Integer maxCategoryLevel) throws QCPromptException {
        //1.判空
        if (dto == null)
            return QCUnifyReturnValue.Warn("对象不能为空");
        if (StringUtils.isBlank(dto.getName()))
            return QCUnifyReturnValue.Warn("栏目名称不能为空");
        
        //2.当父ID大于0时
        if (dto.getPid() > 0) {
            //2.1 判断父ID是否存在
            if (!hasIdExist(dto.getPid()))
                return QCUnifyReturnValue.Warn("指定的上级栏目ID不存在");
            
            //2.2 判断当前添加的栏目是第几层级，超过支持最大层级数则提示
            Integer currentLevel = getCurrentLevel(dto.getPid(),0x1);
            if (currentLevel > maxCategoryLevel)
                return QCUnifyReturnValue.Warn("当前只支持最多到第二级栏目");
        }
        
        //3.判断同一层级中栏目名称不能重复
        if (isNameHasExist(dto.getName(), 0x0, dto.getPid()))
            return QCUnifyReturnValue.Warn("栏目名称已存在，名称不能相同");
        
        //4.判断是否进行版面设计,进行版面设计判断josn格式是否正确
        if (!StringUtils.isBlank(dto.getLayout())) {
            try {
                JSON.parse(dto.getLayout());
                // JSON格式正确
            } catch (JSONException e) {
                // JSON格式不正确
                return QCUnifyReturnValue.Warn("栏版面配置josn格式错误");
            }
        }
        
        //5.判断是否进行文章显示配置,进行文章显示配置判断josn格式是否正确
        if (!StringUtils.isBlank(dto.getArticle())) {
            try {
                JSON.parse(dto.getArticle());
                // JSON格式正确
            } catch (JSONException e) {
                // JSON格式不正确
                return QCUnifyReturnValue.Warn("文章显示配置josn格式错误");
            }
        }

        //6.DTO转换为Entity
        Category en = CategoryMapper.MAPPER.CategoryAddDtoToEntity(dto);
        
        //7.判断是否有栏目封面，如有则判断封面是否存在
        // 如果封面文件无效或不存在自动设置为空，不进行提示.
        if (!hasCoverExist(dto.getCover())) {
            en.setCover(0x0);
        }

        //8.生成栏目ID，获取数据库中的最大id+1后赋值
        en.setId(genereateId());

        //9.保存栏目信息
        if (repository.insert(en) < 0x1)
            return QCUnifyReturnValue.Warn("保存失败");
        return QCUnifyReturnValue.Success();
    }

    /**
     * 计算当前添加/修改的栏目所处的层级数
     * @param parentId 父ID
     * @param level 层级数，默认从第一层（根栏目）开始计算
     * @return 当前部门所处层级
     */
    private Integer getCurrentLevel(Integer parentId,Integer level){
        Integer currentLevel = level + 0x1;
        //获取父栏目
        Category pCategory = repository.selectById(parentId);
        //如果父栏目还有上级，再计算层级
        if (pCategory.getPid() != null && pCategory.getPid() > 0x0){
            currentLevel = getCurrentLevel(pCategory.getPid(),currentLevel);
        }
        return currentLevel;
    }

    /**
     * 修改栏目
     *
     * @param dto 栏目信息
     * @return 成功返回null
     * @author QuCheng Tech
     * @since 2023/5/27
     */
    public String update(CategoryDto dto,Integer maxCategoryLevel) throws QCPromptException {
        //1.判空
        if (dto == null)
            return QCUnifyReturnValue.Warn("对象不能为空");
        if (dto.getId() < 0x1)
            return QCUnifyReturnValue.Warn("栏目ID不能为空");
        if (StringUtils.isBlank(dto.getName()))
            return QCUnifyReturnValue.Warn("栏目名称不能为空");

        //2.当父ID大于0时
        if (dto.getPid() > 0) {
            //判断父级目录是否为自身及自身子级
            if (dto.getId() == dto.getPid())
                return QCUnifyReturnValue.Warn("父级栏目设置不能为自身");
            // 自身子级以及子级id集合
            List<Integer> categoryChildIds = getSelfAndChildIds(dto.getId());
            //结果集移除自身id
            categoryChildIds.remove(Integer.valueOf(dto.getPid()));
            //判断设置的父级id是否为自身子级
            if (categoryChildIds.contains(dto.getPid())) {
                return QCUnifyReturnValue.Warn("父级栏目设置不能为自身子级栏目");
            }
            
            //2.1 判断父ID是否存在
            if (!hasIdExist(dto.getPid()))
                return QCUnifyReturnValue.Warn("指定的上级栏目ID不存在");

            //2.2 判断当前添加的栏目是第几层级，超过支持最大层级数则提示
            Integer currentLevel = getCurrentLevel(dto.getPid(),0x1);
            if (currentLevel > maxCategoryLevel)
                return QCUnifyReturnValue.Warn("当前只支持最多到第二级栏目");
        }

        //DTO转换为Entity
        Category en = CategoryMapper.MAPPER.CategoryDtoToEntity(dto);
        
        //判断修改的栏目是否存在
        if (!hasIdExist(en.getId()))
            return QCUnifyReturnValue.Warn("修改的栏目ID不存在");
        //判断名称不能重复
        if (isNameHasExist(en.getName(), en.getId(), en.getPid()))
            return QCUnifyReturnValue.Warn("栏目名称已存在，名称不能相同");
        //判断父栏目ID是否存在
        if (en.getPid() != null) {
            if (!hasIdExist(en.getPid()))
                return QCUnifyReturnValue.Warn("指定的上级栏目ID不存在");
        } else {
            en.setPid(0x0);
        }
        //判断是否进行版面设计,进行版面设计判断josn格式是否正确
        if (!StringUtils.isBlank(dto.getLayout())) {
            try {
                JSON.parse(dto.getLayout());
                // JSON格式正确
            } catch (JSONException e) {
                // JSON格式不正确
                return QCUnifyReturnValue.Warn("栏版面配置josn格式错误");
            }
        }
        //判断是否进行文章显示配置,进行文章显示配置判断josn格式是否正确
        if (!StringUtils.isBlank(dto.getArticle())) {
            try {
                JSON.parse(dto.getArticle());
                // JSON格式正确
            } catch (JSONException e) {
                // JSON格式不正确
                return QCUnifyReturnValue.Warn("文章显示配置josn格式错误");
            }
        }
        
        //判断是否有栏目封面，如有序判断封面是否存在
        //如果封面文件无效或不存在自动设置为空，不进行提示.
        if (!hasCoverExist(dto.getCover())) {
            en.setCover(0x0);
        }

        repository.updateById(en);

        return QCUnifyReturnValue.Success();
    }

    /**
     * 在其他项目中使用微服务之间调用方式, platform中的/qc/file/get方法返回封面文件信息,判断封面文件是否有效
     *
     * @param cover: 封面文件id
     * @return boolean true表示已存在，false表示不存在
     * @author QcCheng Tech
     * @date 2023/10/18
     */
    public boolean hasCoverExist(int cover) throws QCPromptException {
        List<ServiceInstance>  instances = discoveryClient.getInstances("module-platform");
        //如果获取到的微服务的实例数为0，抛出异常提示
        if(instances==null || instances.size()<0x1)
            throw new QCPromptException("调用module-platform微服务时无任何有效的实例。");

        ServiceInstance service = instances.get(0);
        String url = "http://" + service.getHost() + ":" + service.getPort() + "/file/get/" + cover;
        ResponseEntity<FileInfoDto> response = restTemplate.getForEntity(url, FileInfoDto.class);
        FileInfoDto fileInfoDto = response.getBody();
        if (fileInfoDto != null)
            return true;
        return false;
    }

    /**
     * 查询当前目录自身以及子级id集合
     *
     * @param Id: 当前目录id
     * @return List<Integer> id集合
     * @author QcCheng Tech
     * @date 2023/7/21
     */
    public List<Integer> getSelfAndChildIds(Integer Id) {
        List<Integer> collectedIds = new ArrayList<>();
        // 获取当前父栏目下的所有子栏目
        LambdaUpdateWrapper<Category> wrapper = new LambdaUpdateWrapper<>();
        wrapper.eq(Category::getPid, Id);
        List<Category> children = repository.selectList(wrapper);

        if (children == null) {
            collectedIds.add(Id); // 将当前栏目ID添加到列表中
        } else {
            for (Category child : children) {
                // 递归遍历子栏目的子栏目并将结果添加到列表中
                collectedIds.addAll(getSelfAndChildIds(child.getId()));
            }
            collectedIds.add(Id); // 将当前栏目ID添加到列表中
        }
        return collectedIds;
    }

    /**
     * 删除栏目
     *
     * @param id            栏目ID
     * @param isLogicDelete 是否为逻辑删除
     * @return 成功返回null
     * @author QuCheng Tech
     * @since 2023/5/27
     */
    public String delete(Integer id, boolean isLogicDelete) {
        if (id == null)
            return QCUnifyReturnValue.Warn("要删除的栏目ID不能为空");

        if (!hasIdExist(id))
            return QCUnifyReturnValue.Warn("要删除的栏目不存在");

        if (isLogicDelete) {
            //逻辑删除，修改状态标记，不删除记录
            if (getChildCategoryCount(id) > 0x0)
                return QCUnifyReturnValue.Warn("当前栏目下还有子栏目，无法进行删除操作");

            LambdaUpdateWrapper<Category> wrapper = new LambdaUpdateWrapper<>();
            wrapper.eq(Category::getId, id);

            wrapper.set(Category::getFlag, ResourceStatusFlagEnum.DELETED);

            repository.update(null, wrapper);
        } else {
            //物理删除，需要判断栏目下是否有子栏目和文章
            if (getChildCategoryCount(id) > 0x0)
                return QCUnifyReturnValue.Warn("当前栏目下还有子栏目，无法进行删除操作");

            if (getCategoryArticleCount(id) > 0x0)
                return QCUnifyReturnValue.Warn("当前栏目下还有文章，无法进行删除操作");

            //如果判断通过，可以删除，需要删除栏目与部门关联关系
            categoryDeptService.deleteDeptsByCategoryId(id);

            repository.deleteById(id);
        }

        return QCUnifyReturnValue.Success();
    }

    /**
     * 获取指定栏目ID的下一级栏目数量，排除已删除栏目
     *
     * @param id 栏目ID
     * @return 下一级栏目数量
     * @author QuCheng Tech
     * @since 2023/5/27
     */
    int getChildCategoryCount(Integer id) {
        LambdaQueryWrapper<Category> wrapper = new LambdaQueryWrapper<>();
        wrapper.select(Category::getId);
        wrapper.eq(Category::getPid, id);
        wrapper.ne(Category::getFlag, ResourceStatusFlagEnum.DELETED);


        //查询数据
        List<Category> list = repository.selectList(wrapper);
        if (list != null && list.size() > 0x0) {
            return list.size();
        }

        return 0x0;
    }

    /***
     * 获取指定栏目下的文章数量，不管文章状态
     *
     * @param categoryId 栏目ID
     * @return int
     * @author QuCheng Tech
     * @since 2023/7/30
     */
    int getCategoryArticleCount(int categoryId) {
        LambdaQueryWrapper<Article> wrapper = new LambdaQueryWrapper<>();
        wrapper.select(Article::getId);
        wrapper.eq(Article::getCid, categoryId);

        //查询数据
        List<Article> list = articleRepository.selectList(wrapper);
        if (list != null && list.size() > 0x0) {
            return list.size();
        }

        return 0x0;
    }

    /**
     * 判断指定的ID是否存在
     *
     * @param id 栏目ID
     * @return true表示已存在，false表示不存在
     * @author QuCheng Tech
     * @since 2023/5/26
     */
    public boolean hasIdExist(Integer id) {
        LambdaQueryWrapper<Category> wrapper = new LambdaQueryWrapper<>();
        wrapper.select(Category::getId);
        wrapper.eq(Category::getId, id);

        Category en = repository.selectOne(wrapper);
        if (en != null)
            return true;

        return false;
    }

    /**
     * 判断栏目名称在同一父栏目下是否重复
     *
     * @param name 名称
     * @param id   ID，新增时设置ID为0，修改时设置ID为记录ID
     * @param pid  父栏目ID
     * @return true表示名称已存在，false表示名称不存在
     * @author QuCheng Tech
     * @since 2023/5/25
     */
    boolean isNameHasExist(String name, Integer id, Integer pid) {
        //验证名称是否重复条件：name=name and id<>id
        LambdaQueryWrapper<Category> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(Category::getPid, pid);
        wrapper.eq(Category::getName, name);
        wrapper.ne(Category::getId, id);

        Category en = repository.selectOne(wrapper);
        if (en != null)
            return true;

        return false;
    }

    /**
     * 生成记录ID，获取数据库表中的最大记录ID+1
     *
     * @return 生成记录ID
     * @author QuCheng Tech
     * @since 2023/5/25
     */
    Integer genereateId() {
        Integer maxRecordId = getMaxId();
        return maxRecordId + 1;
    }

    /**
     * 获取数据库表中的最大ID值，没有记录时返回0
     *
     * @return 返回数据库表中的最大ID值
     * @author QuCheng Tech
     * @since 2023/5/25
     */
    Integer getMaxId() {
        LambdaQueryWrapper<Category> wrapper = new LambdaQueryWrapper<>();
        wrapper.select(Category::getId);
        wrapper.orderByDesc(Category::getId);
        Category en = repository.selectOne(wrapper);
        if (en != null)
            return en.getId();

        return 0x0;
    }

    /**
     * 获取指定栏目下的所有子栏目信息（状态正常的）
     * @param pid 父栏目id
     * @return 子栏目列表
     * @since 2024/1/12
     */
    public List<CategoryDto> getChildCategories(Integer pid){
        LambdaQueryWrapper<Category> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(Category::getPid,pid);
        wrapper.eq(Category::getFlag,ResourceStatusFlagEnum.NORMAL);
        List<Category> ens = repository.selectList(wrapper);
        if (CollectionUtils.isNotEmpty(ens))
            return CategoryMapper.MAPPER.toDtoList(ens);
        
        return null;
    }
}
